#include "pila.h"
#include <stdio.h>
#include <stdlib.h>

struct _pila {
    void** datos;
    size_t tamanio;
    size_t cantidad;
};

// Crea una pila.
// Post: devuelve una nueva pila vacía.
pila_t* pila_crear(){
		pila_t* pila = malloc(sizeof(pila_t));
		if (pila == NULL) return NULL;
		pila->cantidad=0;
		pila->datos=malloc(5 * sizeof(void*));
		if (pila->datos == NULL) {
			free(pila);
			return NULL;
		}
		pila->tamanio = 5;
		return pila;
}

//Cambia el tamanio de la pila
//Pre: la pila fue creada
//Post: la pila cambio de tamanio (se multiplica por la variable tamanio) 
//o devuelve false si hubo algun error
bool redimensionar_pila(pila_t *pila, size_t tamanio){
		void** aux = realloc (pila->datos, sizeof(void*) * tamanio);
		if (aux == NULL) return false;
		pila->datos = aux;
		pila->tamanio = tamanio;
		return true;
}

// Destruye la pila.
// Pre: la pila fue creada.
// Post: se eliminaron todos los elementos de la pila.
void pila_destruir(pila_t *pila){
		free(pila->datos);
		free(pila);
}

// Devuelve verdadero o falso, según si la pila tiene o no elementos apilados.
// Pre: la pila fue creada.
bool pila_esta_vacia(const pila_t *pila){
		if (pila->cantidad != 0) return false;
		return true;
}

// Agrega un nuevo elemento a la pila. Devuelve falso en caso de error.
// Pre: la pila fue creada.
// Post: se agregó un nuevo elemento a la pila, valor es el nuevo tope.
bool pila_apilar(pila_t *pila, void* valor){
	if (pila->cantidad == pila->tamanio) {
		if ( ! redimensionar_pila(pila,pila->tamanio*2)) return false;
	}
	pila->datos[pila->cantidad] = valor;
	pila->cantidad++;
	return true;		
}

// Obtiene el valor del tope de la pila. Si la pila tiene elementos,
// se devuelve el valor del tope. Si está vacía devuelve NULL.
// Pre: la pila fue creada.
// Post: se devolvió el valor del tope de la pila, cuando la pila no está
// vacía, NULL en caso contrario.
void* pila_ver_tope(const pila_t *pila){
	if (pila_esta_vacia(pila)) return NULL;
	return pila->datos[(pila->cantidad-1)];
}

// Saca el elemento tope de la pila. Si la pila tiene elementos, se quita el
// tope de la pila, y se devuelve ese valor. Si la pila está vacía, devuelve 
// NULL.
// Pre: la pila fue creada.
// Post: si la pila no estaba vacía, se devuelve el valor del tope anterior 
// y la pila contiene un elemento menos.
void* pila_desapilar(pila_t *pila){
	if (pila_esta_vacia(pila)) return NULL;
	pila->cantidad--;
	if ((pila->tamanio > 5) && (pila->cantidad <= (pila->tamanio / 4))) {
		redimensionar_pila(pila, pila->tamanio/2);
	}
	return pila->datos[(pila->cantidad)];
}

